import aiohttp
import json
import logging
from typing import Dict, Optional, Union, Any
from dataclasses import dataclass

@dataclass
class WeatherResponse:
    """天气响应数据结构"""
    precipitation: float  # 降水量
    temperature: float   # 温度
    pressure: int       # 气压
    humidity: int       # 湿度
    wind_direction: str  # 风向
    wind_direction_degree: int  # 风向度
    wind_speed: float   # 风速
    wind_scale: str     # 风力等级
    place: str          # 地点
    code: int          # 状态码
    msg: Optional[str] = None  # 错误信息

class WeatherAPI:
    """天气查询 API 工具类"""
    
    BASE_URL = "https://cn.apihz.cn/api/tianqi/tqyb.php"
    DEFAULT_ID = "88888888"
    DEFAULT_KEY = "88888888"
    
    @staticmethod
    async def _parse_response(response: aiohttp.ClientResponse) -> Dict[str, Any]:
        """解析 API 响应"""
        content_type = response.headers.get('Content-Type', '').lower()
        
        if response.status != 200:
            text = await response.text()
            raise RuntimeError(f"API返回错误状态码: {response.status}, 响应: {text}")
            
        try:
            if 'application/json' in content_type:
                return await response.json()
            else:
                # 尝试解析响应内容为 JSON，即使 Content-Type 不是 JSON
                text = await response.text()
                return json.loads(text)
        except json.JSONDecodeError as e:
            raise RuntimeError(f"解析响应失败: {str(e)}, 响应内容: {text[:200]}")
    
    @staticmethod
    async def get_weather(province: str, city: str) -> WeatherResponse:
        """获取指定地区的天气信息"""
        if not province or not city:
            raise ValueError("省份和城市名称不能为空")
            
        params = {
            "id": WeatherAPI.DEFAULT_ID,
            "key": WeatherAPI.DEFAULT_KEY,
            "sheng": province,
            "place": city
        }
        
        timeout = aiohttp.ClientTimeout(total=10)  # 10秒超时
        try:
            async with aiohttp.ClientSession(timeout=timeout) as session:
                async with session.get(WeatherAPI.BASE_URL, params=params, ssl=False) as response:
                    data = await WeatherAPI._parse_response(response)
                    
                    # 检查响应数据结构
                    if not isinstance(data, dict):
                        raise RuntimeError(f"非法的响应格式: {data}")
                        
                    if data.get("code") != 200:
                        raise RuntimeError(data.get("msg", "API返回错误"))
                    
                    try:
                        return WeatherResponse(
                            precipitation=float(data.get("precipitation", 0)),
                            temperature=float(data.get("temperature", 0)),
                            pressure=int(data.get("pressure", 0)),
                            humidity=int(data.get("humidity", 0)),
                            wind_direction=str(data.get("windDirection", "")),
                            wind_direction_degree=int(data.get("windDirectionDegree", 0)),
                            wind_speed=float(data.get("windSpeed", 0)),
                            wind_scale=str(data.get("windScale", "")),
                            place=str(data.get("place", "")),
                            code=int(data.get("code", 0))
                        )
                    except (ValueError, TypeError) as e:
                        raise RuntimeError(f"数据格式错误: {str(e)}, 数据: {data}")
                    
        except asyncio.TimeoutError:
            raise RuntimeError("请求超时")
        except aiohttp.ClientError as e:
            raise RuntimeError(f"网络请求错误: {str(e)}")
        except Exception as e:
            raise RuntimeError(f"获取天气信息失败: {str(e)}")

    @staticmethod
    def format_weather(weather: WeatherResponse) -> str:
        """格式化天气信息为易读字符串"""
        return (
            f"📍 地点：{weather.place}\n"
            f"🌡️ 温度：{weather.temperature}°C\n"
            f"💧 湿度：{weather.humidity}%\n"
            f"🌧️ 降水量：{weather.precipitation}mm\n"
            f"💨 风向：{weather.wind_direction} ({weather.wind_direction_degree}°)\n"
            f"🌬️ 风速：{weather.wind_speed}m/s ({weather.wind_scale})"
        )


# 测试代码
# async def test_weather_api():
#     try:
#         weather = await WeatherAPI.get_weather("广东", "广州")
#         print(WeatherAPI.format_weather(weather))
#     except Exception as e:
#         print(f"❌ 获取天气信息失败: {str(e)}")


# if __name__ == "__main__":
#     import asyncio
#     asyncio.run(test_weather_api())